#include <iostream>
#include <dlfcn.h>
#include <stdexcept>
#include "glutils.hpp"
#include "exceptions.hpp"
#include "GraphOpenGl.hpp"

Graphics::Graphics(int, char**, int w, int h) :
    _w(w),
    _h(h),
    _font(0)
{
  if (SDL_Init(SDL_INIT_VIDEO) == -1)
    throw LibraryInteralError("OpenGL", SDL_GetError());
  if (TTF_Init() == -1)
    throw "Erreur lors du chargement de la SDL_TTF";
  if (!SDL_SetVideoMode(_w, _h ,32, SDL_OPENGL))
    throw LibraryInteralError("OpenGL", SDL_GetError());
}

void Graphics::loadImages(const std::map<IGraph::Image, std::string> &loadMap)
{
  std::map<IGraph::Image, std::string>::const_iterator it;

  for (it = loadMap.begin() ; it != loadMap.end() ; ++it)
    {
      _imgMap[it->first] = GLUtils::loadTexture((it->second).c_str());
      if (_imgMap[it->first] == 0)
        {
          throw ImageNotFoundExceptions(it->second);
        }
    }
}

void Graphics::loadFont(const std::string &fontPath)
{
  _font = TTF_OpenFont(fontPath.c_str(), 25);
  if (_font == 0)
    throw FontNotFoundExceptions(fontPath);
}

void Graphics::writeText(char r, char g, char b, const std::string &text, int x, int y)
{
  SDL_Color c;

  c.r = r;
  c.g = g;
  c.b = b;
  GLUtils::writeTextGL(text, _font, c, x, y);
}

Point Graphics::getTextSize(const std::string &text) const
{
  Point p;
  SDL_Color c = {0, 0, 0, 0};
  SDL_Surface *t;

  t = TTF_RenderText_Blended(_font, text.c_str(), c);
  p.x = t->w;
  p.y = t->h;
  return (p);
}

void Graphics::pause()
{
  SDL_Event ev;

   while (1)
     {
       SDL_WaitEvent(&ev);
       if (ev.type == SDL_QUIT || ev.type == SDL_KEYDOWN)
         break;
       SDL_GL_SwapBuffers();
     }
}

void Graphics::clearScreen(char r, char g, char b)
{
  float		rgb[3];

  rgb[0] = r / 255.0;
  rgb[1] = g / 255.0;
  rgb[2] = b / 255.0;
  glClearColor(rgb[0], rgb[1], rgb[2], 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
}

void Graphics::openWindow()
{
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, _w, _h, 0, 0, 1);
  glDisable(GL_DEPTH_TEST);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void Graphics::display()
{
  SDL_GL_SwapBuffers();
}

void Graphics::drawBlock(IGraph::Image img, int x, int y)
{
  std::map<IGraph::Image, GLuint>::iterator it;
  int	x1,y1,x2,y2;

  if ((it = _imgMap.find(img)) == _imgMap.end())
    return;
  glBindTexture(GL_TEXTURE_2D, it->second);
  x1 = 0 + x;
  y2 = 0 + y;
  y1 = 16 + y;
  x2 = 16 + x;
  glBegin(GL_QUADS);
    glTexCoord2d(0, 0);
    glVertex2f(x1, y1);
    glTexCoord2d(1, 0);
    glVertex2f(x2, y1);
    glTexCoord2d(1, 1);
    glVertex2f(x2, y2);
    glTexCoord2d(0, 1);
    glVertex2f(x1, y2);
  glEnd();
}

void Graphics::wait(unsigned int d) const
{
  SDL_Delay(d);
}

Graphics::~Graphics()
{
  TTF_CloseFont(_font);
  SDL_Quit();
  TTF_Quit();
}

IGraph::Event Graphics::getNextEvent()
{
  while (SDL_PollEvent(&e))
    {
      if (e.type == SDL_QUIT)
        return (IGraph::QUIT);
      if (e.type == SDL_KEYDOWN)
        {
          if (e.key.keysym.sym == SDLK_UP)
            return IGraph::UP;
          if (e.key.keysym.sym == SDLK_DOWN)
            return IGraph::DOWN;
          if (e.key.keysym.sym == SDLK_LEFT)
            return IGraph::LEFT;
          if (e.key.keysym.sym == SDLK_RIGHT)
            return IGraph::RIGHT;
          if (e.key.keysym.sym == SDLK_ESCAPE)
            return IGraph::QUIT;
        }
    }
  return (IGraph::NONE);
}

unsigned int Graphics::getCurrentTime() const
{
  return (SDL_GetTicks());
}
